﻿
namespace Go
{
	public class GameState
	{
		public Board board;
		public Player next_player;
		public GameState previous_state;
		public Move last_move;
		public GameState(Board board, Player next_player, GameState previous, Move move)
		{
			this.board = board;
			this.next_player = next_player;
			this.previous_state = previous;
			this.last_move = move;
		}

		public GameState apply_move(Move move)
		{
			Board next_board;
			if (move.is_play)
			{
				next_board = board.DeepCopy();
				next_board.place_stone(next_player, move.point);
			}
			else
			{
				next_board = this.board;
			}
			return new GameState(next_board, next_player.other(), this, move);
		}

		public static GameState new_game(int board_size)
		{
			var board = new Board(board_size, board_size);
			return new GameState(board, Player.black, null, null);
		}

		public bool is_over()
		{
			if (last_move == null)
				return false;
			if (last_move.is_resign)
				return true;

			var second_last_move = previous_state.last_move;
			if (second_last_move == null)
				return false;

			return last_move.is_pass && second_last_move.is_pass;
		}

		public bool is_move_self_capture(Player player, Move move)
		{
			if (!move.is_play)
				return false;
			var next_board = board.DeepCopy();

			next_board.place_stone(player, move.point);
			var new_string = next_board.get_go_string(move.point);

			return new_string.num_liberties == 0;
		}

		public bool does_move_violate_ko(Player player, Move move)
		{
			if (!move.is_play)
				return false;
			var next_board = board.DeepCopy();

			next_board.place_stone(player, move.point);

			var past_state = previous_state;
			while (past_state != null)
			{
				if (past_state.next_player == next_player.other() && past_state.board == next_board)
					return true;
				past_state = past_state.previous_state;
			}
			return false;
		}

		public bool is_valid_move(Move move)
		{
			if (is_over())
				return false;

			if (move.is_pass || move.is_resign)
				return true;

			return (
				board.get(move.point) == Player.none &&
				!is_move_self_capture(next_player, move) &&
				!does_move_violate_ko(next_player, move));
		}
	}
}
